#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>


#define ANGLE_FRAME_HEADER 0xAA  // 角度帧固定帧头
#define ANGLE_FRAME_TAIL   0x55  // 角度帧固定帧尾
#define FRAME_LENGTH       6     // 角度帧固定长度：1字节头 + 2字节S1 + 2字节S2 + 1字节尾


uint8_t Serial_RxPacket[FRAME_LENGTH];  // 角度帧接收缓存（固定6字节）
uint8_t Serial_RxFlag;                  // 角度帧接收完成标志


void Serial_Init(void)
{
    // 1. 使能外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    // 2. 配置TX引脚（PA9）：复用推挽输出
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 3. 配置RX引脚（PA10）：上拉输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 4. 配置串口参数（115200波特率，8位数据位，1位停止位，无校验）
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  // 保留收发功能
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStructure);
    
    // 5. 使能串口接收中断（RXNE：接收数据非空）
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    // 6. 配置中断优先级（分组2，抢占1，子优先级1）
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    
    // 7. 使能串口
    USART_Cmd(USART1, ENABLE);
}

/************************** 基础发送函数（保留，用于调试或扩展） **************************/
// 发送单个字节
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1, Byte);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  // 等待发送完成
}

// 发送字节数组（支持二进制数据发送，如角度帧）
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
    for (uint16_t i = 0; i < Length; i ++)
    {
        Serial_SendByte(Array[i]);
    }
}

// 发送字符串（用于调试信息输出）
void Serial_SendString(char *String)
{
    for (uint8_t i = 0; String[i] != '\0'; i ++)
    {
        Serial_SendByte(String[i]);
    }
}

// 幂运算函数（用于数字发送）
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
    uint32_t Result = 1;
    while (Y --)
    {
        Result *= X;
    }
    return Result;
}

// 发送数字（用于调试，指定数字长度）
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
    for (uint8_t i = 0; i < Length; i ++)
    {
        Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    }
}

// 重定向fputc（支持printf函数，用于调试）
int fputc(int ch, FILE *f)
{
    Serial_SendByte(ch);
    return ch;
}

// 格式化打印函数（用于调试信息输出）
void Serial_Printf(char *format, ...)
{
    char String[100];
    va_list arg;
    va_start(arg, format);
    vsprintf(String, format, arg);
    va_end(arg);
    Serial_SendString(String);
}

void USART1_IRQHandler(void)
{
    static uint8_t RxState = 0;  // 接收状态：0-等待角度帧头，1-接收帧数据，2-等待角度帧尾
    static uint8_t RxCount = 0;  // 已接收字节计数器（0~5，对应6字节帧）

  
    if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
    {
        uint8_t RxData = USART_ReceiveData(USART1);  // 读取当前接收字节

        switch (RxState)
        {
            // 状态0：等待角度帧头（0xAA）
            case 0:
                if (RxData == ANGLE_FRAME_HEADER)  // 检测到角度帧头
                {
                    Serial_RxPacket[RxCount++] = RxData;  // 存入帧头
                    RxState = 1;                          // 切换到"接收数据"状态
                }
                // 不是角度帧头，直接丢弃（不改变状态）
                break;

            // 状态1：接收帧中间4字节数据（S1低8位、S1高8位、S2低8位、S2高8位）
            case 1:
                Serial_RxPacket[RxCount++] = RxData;  // 存入当前数据字节
                // 接收5字节后（帧头+4数据），切换到"等待帧尾"状态
                if (RxCount >= FRAME_LENGTH - 1)
                {
                    RxState = 2;
                }
                break;

            // 状态2：等待角度帧尾（0x55）
            case 2:
                if (RxData == ANGLE_FRAME_TAIL)  // 检测到正确帧尾
                {
                    Serial_RxPacket[RxCount] = RxData;  // 存入帧尾
                    Serial_RxFlag = 1;                  // 标记角度帧接收完成
                }
                // 无论帧尾是否正确，都重置状态（准备下次接收）
                RxState = 0;
                RxCount = 0;
                break;
        }

        USART_ClearITPendingBit(USART1, USART_IT_RXNE);  // 清除中断标志
    }
}
